package com.cloudcentral.util;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.Getter;

import java.util.Calendar;

/**
 * Create by WEI
 * 2023/4/7 10:34
 */
@Data
@Schema(description = "响应结果")
public class Result<T> {
  @Schema(description = "状态码", example = "200")
  private final int code;
  @Schema(description = "内容")
  private final T data;
  @Schema(description = "描述", example = "请求成功")
  private final String msg;
  @Schema(description = "成功")
  private final boolean success;
  @Schema(description = "时间戳")
  private final long timestamp;

  public Result(int code, T data, String msg, boolean success) {
    this.code = code;
    this.data = data;
    this.msg = msg;
    this.success = success;
    this.timestamp = Calendar.getInstance().getTime().getTime();
  }

  public static <T> Result<T> ok(T data) {
    if (data instanceof Boolean result) {
      int code = result ? ResultCode.OK.getCode() : ResultCode.FAIL.getCode();
      String msg = result ? ResultCode.OK.getName() : ResultCode.FAIL.getName();
      return new Result<>(code, data, msg, result);
    }
    return new Result<>(ResultCode.OK.getCode(), data, ResultCode.OK.getName(), true);
  }

  public static <T> Result<T> ok() {
    return new Result<>(ResultCode.OK.getCode(), null, ResultCode.OK.getName(), true);
  }

  public static <T> Result<T> fail(String msg) {
    return new Result<>(ResultCode.FAIL.getCode(), null, msg, false);
  }

  public static <T> Result<T> fail(T data) {
    return new Result<>(ResultCode.FAIL.getCode(), data, ResultCode.FAIL.getName(), false);
  }

  public static <T> Result<T> fail(T data, String msg) {
    return new Result<>(ResultCode.FAIL.getCode(), data, msg, false);
  }

  public static <T> Result<T> fail() {
    return new Result<>(ResultCode.FAIL.getCode(), null, ResultCode.FAIL.getName(), false);
  }

  public static <T> Result<T> invalid(String msg) {
    return new Result<>(ResultCode.INVALID.getCode(), null, msg, false);
  }

  public static <T> Result<T> invalid(T data) {
    return new Result<>(ResultCode.INVALID.getCode(), data, ResultCode.INVALID.getName(), false);
  }

  public static <T> Result<T> invalid(T data, String msg) {
    return new Result<>(ResultCode.INVALID.getCode(), data, msg, false);
  }

  public static <T> Result<T> invalid() {
    return new Result<>(ResultCode.INVALID.getCode(), null, ResultCode.INVALID.getName(), false);
  }

  public static <T> Result<T> notfound(String msg) {
    return new Result<>(ResultCode.NOTFOUND.getCode(), null, msg, false);
  }

  public static <T> Result<T> notfound(T data) {
    return new Result<>(ResultCode.NOTFOUND.getCode(), data, ResultCode.NOTFOUND.getName(), false);
  }

  public static <T> Result<T> notfound(T data, String msg) {
    return new Result<>(ResultCode.NOTFOUND.getCode(), data, msg, false);
  }

  public static <T> Result<T> notfound() {
    return new Result<>(ResultCode.NOTFOUND.getCode(), null, ResultCode.NOTFOUND.getName(), false);
  }

  public static <T> Result<T> exception(String msg) {
    return new Result<>(ResultCode.EXCEPTION.getCode(), null, msg, false);
  }

  public static <T> Result<T> exception(T data) {
    return new Result<>(ResultCode.EXCEPTION.getCode(), data, ResultCode.EXCEPTION.getName(), false);
  }

  public static <T> Result<T> exception(T data, String msg) {
    return new Result<>(ResultCode.EXCEPTION.getCode(), data, msg, false);
  }

  public static <T> Result<T> exception() {
    return new Result<>(ResultCode.EXCEPTION.getCode(), null, ResultCode.EXCEPTION.getName(), false);
  }

  public static <T> Result<T> duplicate(String msg) {
    return new Result<>(ResultCode.DUPLICATE.getCode(), null, msg, false);
  }

  public static <T> Result<T> duplicate(T data) {
    return new Result<>(ResultCode.DUPLICATE.getCode(), data, ResultCode.DUPLICATE.getName(), false);
  }

  public static <T> Result<T> duplicate(T data, String msg) {
    return new Result<>(ResultCode.DUPLICATE.getCode(), data, msg, false);
  }

  public static <T> Result<T> duplicate() {
    return new Result<>(ResultCode.DUPLICATE.getCode(), null, ResultCode.DUPLICATE.getName(), false);
  }

  public static <T> Result<T> denied(String msg) {
    return new Result<>(ResultCode.DENIED.getCode(), null, msg, false);
  }

  public static <T> Result<T> denied(T data) {
    return new Result<>(ResultCode.DENIED.getCode(), data, ResultCode.DENIED.getName(), false);
  }

  public static <T> Result<T> denied(T data, String msg) {
    return new Result<>(ResultCode.DENIED.getCode(), data, msg, false);
  }

  public static <T> Result<T> denied() {
    return new Result<>(ResultCode.DENIED.getCode(), null, ResultCode.DENIED.getName(), false);
  }

  @Getter
  @Schema(description = "响应状态")
  public enum ResultCode {
    OK("请求成功", 200),
    FAIL("请求失败", 400),
    INVALID("尚未登录", 401),
    DENIED("拒绝访问", 403),
    NOTFOUND("资源为空", 404),
    EXCEPTION("程序异常", 500),
    DUPLICATE("数据重复", 501);

    @Schema(description = "描述", example = "请求成功")
    private final String name;
    @Schema(description = "状态码", example = "200")
    private final int code;

    ResultCode(String name, int code) {
      this.name = name;
      this.code = code;
    }
  }
}
